home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / include / glibmm-2.4 / glibmm / thread.h < prev    next >
Encoding:
C/C++ Source or Header  |  2006-04-20  |  27.5 KB  |  1,083 lines

  1. // -*- c++ -*-
  2. // Generated by gtkmmproc -- DO NOT MODIFY!
  3. #ifndef _GLIBMM_THREAD_H
  4. #define _GLIBMM_THREAD_H
  5.  
  6.  
  7. /* $Id: thread.hg,v 1.13 2005/01/21 12:48:05 murrayc Exp $ */
  8.  
  9. /* Copyright (C) 2002 The gtkmm Development Team
  10.  *
  11.  * This library is free software; you can redistribute it and/or
  12.  * modify it under the terms of the GNU Library General Public
  13.  * License as published by the Free Software Foundation; either
  14.  * version 2 of the License, or (at your option) any later version.
  15.  *
  16.  * This library is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19.  * Library General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU Library General Public
  22.  * License along with this library; if not, write to the Free
  23.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26.  
  27. #include <glib/gthread.h>
  28. #include <cstddef>
  29.  
  30. #include <sigc++/sigc++.h>
  31. #include <glibmm/error.h>
  32. #include <glibmm/timeval.h>
  33.  
  34. /* Shadow THREAD_PRIORITY_NORMAL macro (from winbase.h).
  35.  */
  36. #if defined(THREAD_PRIORITY_NORMAL) && !defined(GLIBMM_MACRO_SHADOW_THREAD_PRIORITY_NORMAL)
  37. enum { GLIBMM_MACRO_DEFINITION_THREAD_PRIORITY_NORMAL = THREAD_PRIORITY_NORMAL };
  38. #undef THREAD_PRIORITY_NORMAL
  39. enum { THREAD_PRIORITY_NORMAL = GLIBMM_MACRO_DEFINITION_THREAD_PRIORITY_NORMAL };
  40. #define THREAD_PRIORITY_NORMAL THREAD_PRIORITY_NORMAL
  41. #define GLIBMM_MACRO_SHADOW_THREAD_PRIORITY_NORMAL 1
  42. #endif
  43.  
  44.  
  45. /** Initializer macro for Glib::StaticMutex.
  46.  * @relates Glib::StaticMutex
  47.  * @hideinitializer
  48.  */
  49. #define GLIBMM_STATIC_MUTEX_INIT { G_STATIC_MUTEX_INIT }
  50.  
  51. /** Initializer macro for Glib::StaticRecMutex.
  52.  * @relates Glib::StaticRecMutex
  53.  * @hideinitializer
  54.  */
  55. #define GLIBMM_STATIC_REC_MUTEX_INIT { G_STATIC_REC_MUTEX_INIT }
  56.  
  57. /** Initializer macro for Glib::StaticRWLock.
  58.  * @relates Glib::StaticRWLock
  59.  * @hideinitializer
  60.  */
  61. #define GLIBMM_STATIC_RW_LOCK_INIT { G_STATIC_RW_LOCK_INIT }
  62.  
  63. /** Initializer macro for Glib::StaticPrivate.
  64.  * @relates Glib::StaticPrivate
  65.  * @hideinitializer
  66.  */
  67. #define GLIBMM_STATIC_PRIVATE_INIT { G_STATIC_PRIVATE_INIT }
  68.  
  69.  
  70. namespace Glib
  71. {
  72.  
  73. /** @addtogroup glibmmEnums Enums and Flags */
  74.  
  75. /** Specifies the priority of a thread.
  76.  * @note It is not guaranteed, that threads with different priorities really
  77.  * behave accordingly. On some systems (e.g. Linux) only <tt>root</tt> can
  78.  * increase priorities. On other systems (e.g. Solaris) there doesn't seem to
  79.  * be different scheduling for different priorities. All in all try to avoid
  80.  * being dependent on priorities.
  81.  * @ingroup glibmmEnums
  82.  */
  83. enum ThreadPriority
  84. {
  85.   THREAD_PRIORITY_LOW,
  86.   THREAD_PRIORITY_NORMAL,
  87.   THREAD_PRIORITY_HIGH,
  88.   THREAD_PRIORITY_URGENT
  89. };
  90.  
  91.  
  92. /*! @var ThreadPriority THREAD_PRIORITY_LOW
  93.  * A priority lower than normal.
  94.  */
  95. /*! @var ThreadPriority THREAD_PRIORITY_NORMAL
  96.  * The default priority.
  97.  */
  98. /*! @var ThreadPriority THREAD_PRIORITY_HIGH
  99.  * A priority higher than normal.
  100.  */
  101. /*! @var ThreadPriority THREAD_PRIORITY_URGENT
  102.  * The highest priority.
  103.  */
  104.  
  105.  
  106. /** @defgroup Threads Threads
  107.  * Thread abstraction; including threads, different mutexes,
  108.  * conditions and thread private data.
  109.  * @{
  110.  */
  111.  
  112. enum NotLock { NOT_LOCK };
  113. enum TryLock { TRY_LOCK };
  114.  
  115. /** Initializes the GLib thread system.
  116.  * Before you use a thread related function in glibmm, you should initialize
  117.  * the thread system.  This is done by calling Glib::thread_init().
  118.  *
  119.  * @note You should only call thread_init() with a non-<tt>0</tt> parameter
  120.  * if you really know what you are doing.
  121.  *
  122.  * @note thread_init() must not be called directly or indirectly as
  123.  * a callback from glibmm.  Also no mutexes may be currently locked while
  124.  * calling thread_init().
  125.  *
  126.  * thread_init() might only be called once.  On the second call it will
  127.  * abort with an error.  If you want to make sure that the thread system
  128.  * is initialized, you can do that too:
  129.  * @code
  130.  * if(!Glib::thread_supported()) Glib::thread_init();
  131.  * @endcode
  132.  * After that line either the thread system is initialized, or the program
  133.  * will abort if no thread system is available in GLib, i.e. either
  134.  * @c G_THREADS_ENABLED is not defined or @c G_THREADS_IMPL_NONE is defined.
  135.  *
  136.  * If no thread system is available and @a vtable is <tt>0</tt> or if not all
  137.  * elements of @a vtable are non-<tt>0</tt>, then thread_init() will abort.
  138.  *
  139.  * @note To use thread_init() in your program, you have to link with the
  140.  * libraries that the command <tt>pkg-config --libs gthread-2.0</tt>
  141.  * outputs.  This is not the case for all the other thread related functions
  142.  * of glibmm.  Those can be used without having to link with the thread
  143.  * libraries.  (You @em have to link with <tt>gthread-2.0</tt> if you actually
  144.  * want to use threads in your application, though.)
  145.  *
  146.  * @param vtable A function table of type @c GThreadFunctions, that provides
  147.  * the entry points to the thread system to be used.
  148.  */
  149. inline void thread_init(GThreadFunctions* vtable = 0);
  150.  
  151. /** Returns whether the thread system is initialized.
  152.  * @return @c true, if the thread system is initialized.
  153.  */
  154. inline bool thread_supported();
  155.  
  156.  
  157. class Mutex;
  158. class RecMutex;
  159. class RWLock;
  160. struct StaticMutex;
  161. struct StaticRecMutex;
  162. struct StaticRWLock;
  163.  
  164.  
  165. /** Exception class for thread-related errors.
  166.  */
  167. class ThreadError : public Glib::Error
  168. {
  169. public:
  170.   enum Code
  171.   {
  172.     AGAIN
  173.   };
  174.  
  175.   ThreadError(Code error_code, const Glib::ustring& error_message);
  176.   explicit ThreadError(GError* gobject);
  177.   Code code() const;
  178.  
  179. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  180. private:
  181.   static void throw_func(GError* gobject);
  182.   friend void wrap_init(); // uses throw_func()
  183. #endif
  184. };
  185.  
  186.  
  187. /** Represents a running thread.
  188.  * An instance of this class can only be obtained with create(), self(),
  189.  * or wrap(GThread*).  It's not possible to delete a Thread object.  If the
  190.  * thread is @em not joinable, its resources will be freed automatically
  191.  * when it exits.  Otherwise, if the thread @em is joinable, you must call
  192.  * join() to avoid a memory leak.
  193.  *
  194.  * @note g_thread_exit() is not wrapped, because that function exits a thread
  195.  * without any cleanup.  That's especially dangerous in C++ code, since the
  196.  * destructors of automatic objects won't be invoked.  Instead, you can throw
  197.  * a Thread::Exit exception, which will be caught by the internal thread
  198.  * entry function.
  199.  *
  200.  * @note You might have noticed that the thread entry slot doesn't have the
  201.  * usual void* return value.  If you want to return any data from your thread
  202.  * you can pass an additional output argument to the thread's entry slot.
  203.  */
  204. class Thread
  205. {
  206. public:
  207.   class Exit;
  208.  
  209.   /** Creates a new thread with the priority <tt>THREAD_PRIORITY_NORMAL</tt>.
  210.    * If @a joinable is @c true, you can wait for this thread's termination by
  211.    * calling join().  Otherwise the thread will just disappear, when ready.
  212.    *
  213.    * The new thread executes the function or method @a slot points to.  You can
  214.    * pass additional arguments using sigc::bind().  If the thread was created
  215.    * successfully, it is returned, otherwise a ThreadError exception is thrown.
  216.    *
  217.    * @param slot A slot to execute in the new thread.
  218.    * @param joinable Should this thread be joinable?
  219.    * @return The new Thread* on success.
  220.    * @throw Glib::ThreadError
  221.    */
  222.   static Thread* create(const sigc::slot<void>& slot, bool joinable);
  223.  
  224.   /** Creates a new thread with the priority @a priority. The stack gets the
  225.    * size @a stack_size or the default value for the current platform, if
  226.    * @a stack_size is <tt>0</tt>.
  227.    *
  228.    * If @a joinable is @c true, you can wait for this thread's termination by
  229.    * calling join().  Otherwise the thread will just disappear, when ready.
  230.    * If @a bound is @c true, this thread will be scheduled in the system scope,
  231.    * otherwise the implementation is free to do scheduling in the process
  232.    * scope.  The first variant is more expensive resource-wise, but generally
  233.    * faster.  On some systems (e.g. Linux) all threads are bound.
  234.    *
  235.    * The new thread executes the function or method @a slot points to.  You can
  236.    * pass additional arguments using sigc::bind().  If the thread was created
  237.    * successfully, it is returned.
  238.    *
  239.    * @note It is not guaranteed, that threads with different priorities really
  240.    * behave accordingly.  On some systems (e.g. Linux) only root can increase
  241.    * priorities.  On other systems (e.g. Solaris) there doesn't seem to be
  242.    * different scheduling for different priorities.  All in all try to avoid
  243.    * being dependent on priorities.  Use <tt>Glib::THREAD_PRIORITY_NORMAL</tt>
  244.    * here as a default.
  245.    *
  246.    * @note Only use the extended
  247.    * create(const sigc::slot<void>&, unsigned long, bool, bool, ThreadPriority)
  248.    * function, when you really can't use the simple
  249.    * create(const sigc::slot<void>&, bool)
  250.    * instead.  The latter overload does not take @a stack_size, @a bound and
  251.    * @a priority as arguments, as they should only be used for cases, where
  252.    * it is inevitable.
  253.    *
  254.    * @param slot A slot to execute in the new thread.
  255.    * @param stack_size A stack size for the new thread, or <tt>0</tt>.
  256.    * @param joinable Should this thread be joinable?
  257.    * @param bound Should this thread be bound to a system thread?
  258.    * @param priority A priority for the thread.
  259.    * @return The new Thread* on success.
  260.    * @throw Glib::ThreadError
  261.    */
  262.   static Thread* create(const sigc::slot<void>& slot, unsigned long stack_size,
  263.                         bool joinable, bool bound, ThreadPriority priority);
  264.  
  265.   /** Returns the Thread* corresponding to the calling thread.
  266.    * @return The current thread.
  267.    */
  268.   static Thread* self();
  269.  
  270.   /** Returns whether the thread is joinable.
  271.    * @return Whether the thread is joinable.
  272.    */
  273.   bool joinable() const;
  274.  
  275.   /** Waits until the thread finishes.
  276.    * Waits until the thread finishes, i.e. the slot, as given to create(),
  277.    * returns or g_thread_exit() is called by the thread.  (Calling
  278.    * g_thread_exit() in a C++ program should be avoided.)  All resources of
  279.    * the thread including the Glib::Thread object are released.  The thread
  280.    * must have been created with <tt>joinable = true</tt>.
  281.    */
  282.   void join();
  283.  
  284.   /** Changes the priority of the thread to @a priority.
  285.    * @note It is not guaranteed, that threads with different priorities really
  286.    * behave accordingly.  On some systems (e.g. Linux) only @c root can
  287.    * increase priorities.  On other systems (e.g. Solaris) there doesn't seem
  288.    * to be different scheduling for different priorities.  All in all try to
  289.    * avoid being dependent on priorities.
  290.    * @param priority A new priority for the thread.
  291.    */
  292.   void set_priority(ThreadPriority priority);
  293.  
  294.   /** Returns the priority of the thread.
  295.    * @return The thread's priority.
  296.    */
  297.   ThreadPriority get_priority() const;
  298.  
  299.   /** Gives way to other threads waiting to be scheduled.
  300.    * This function is often used as a method to make busy wait less evil.  But
  301.    * in most cases, you will encounter, there are better methods to do that.
  302.    * So in general you shouldn't use this function.
  303.    */
  304.   static void yield();
  305.  
  306.   GThread*       gobj()       { return &gobject_; }
  307.   const GThread* gobj() const { return &gobject_; }
  308.  
  309. private:
  310.   GThread gobject_;
  311.  
  312.   // Glib::Thread can neither be constructed nor deleted.
  313.   Thread();
  314.   void operator delete(void*, size_t);
  315.  
  316.   // noncopyable
  317.   Thread(const Thread&);
  318.   Thread& operator=(const Thread&);
  319. };
  320.  
  321. /** %Exception class used to exit from a thread.
  322.  * @code
  323.  * throw Glib::Thread::Exit();
  324.  * @endcode
  325.  * Write this if you want to exit from a thread created by Thread::create().
  326.  * Of course you must make sure not to catch Thread::Exit by accident, i.e.
  327.  * when using <tt>catch(...)</tt> somewhere in your code.
  328.  */
  329. class Thread::Exit
  330. {};
  331.  
  332. /** @relates Glib::Thread */
  333. Thread* wrap(GThread* gobject);
  334.  
  335.  
  336. /** Like Glib::Mutex, but can be defined at compile time.
  337.  * Use @c GLIBMM_STATIC_MUTEX_INIT to initialize a StaticMutex:
  338.  * @code
  339.  * Glib::StaticMutex mutex = GLIBMM_STATIC_MUTEX_INIT;
  340.  * @endcode
  341.  * A StaticMutex can be used without calling Glib::thread_init(), it will
  342.  * silently do nothing then.  That will also work when using the implicit
  343.  * conversion to Mutex&, thus you can safely use Mutex::Lock with a
  344.  * StaticMutex.
  345.  */
  346. struct StaticMutex
  347. {
  348.   void lock();
  349.   bool trylock();
  350.   void unlock();
  351.  
  352.   operator Mutex&();
  353.  
  354.   GStaticMutex* gobj() { return &gobject_; }
  355.  
  356. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  357.   // Must be public to allow initialization at compile time.
  358.   GStaticMutex gobject_;
  359. #endif
  360. };
  361.  
  362. /** Represents a mutex (mutual exclusion).
  363.  * It can be used to protect data against shared access.  Try to use
  364.  * Mutex::Lock instead of calling lock() and unlock() directly --
  365.  * it will make your life much easier.
  366.  *
  367.  * @note Before creating a Glib::Mutex, Glib::thread_init() has to be called.
  368.  *
  369.  * @note Glib::Mutex is not recursive, i.e. a thread will deadlock, if it
  370.  * already has locked the mutex while calling lock().  Use Glib::RecMutex
  371.  * instead, if you need recursive mutexes.
  372.  */
  373. class Mutex
  374. {
  375. public:
  376.   class Lock;
  377.  
  378.   Mutex();
  379.   ~Mutex();
  380.  
  381.   /** Locks the mutex.
  382.    * If mutex is already locked by another thread, the current thread will
  383.    * block until mutex is unlocked by the other thread.
  384.    * @see Mutex::Lock
  385.    */
  386.   void lock();
  387.  
  388.   /** Tries to lock the mutex.
  389.    * If the mutex is already locked by another thread, it immediately returns
  390.    * @c false.  Otherwise it locks the mutex and returns @c true.
  391.    * @return Whether the mutex could be locked.
  392.    * @see Mutex::Lock
  393.    */
  394.   bool trylock();
  395.  
  396.   /** Unlocks the mutex.
  397.    * If another thread is blocked in a lock() call for this mutex, it will be
  398.    * woken and can lock the mutex itself.
  399.    * @see Mutex::Lock
  400.    */
  401.   void unlock();
  402.  
  403.   GMutex* gobj() { return gobject_; }
  404.  
  405. private:
  406.   GMutex* gobject_;
  407.  
  408.   // noncopyable
  409.   Mutex(const Mutex&);
  410.   Mutex& operator=(const Mutex&);
  411. };
  412.  
  413. /** Utility class for exception-safe mutex locking.
  414.  * @par Usage example:
  415.  * @code
  416.  * {
  417.  *   Glib::Mutex::Lock lock (mutex); // calls mutex.lock()
  418.  *   do_something();
  419.  * } // the destructor calls mutex.unlock()
  420.  * @endcode
  421.  * As you can see, the compiler takes care of the unlocking.  This is not
  422.  * only exception safe but also much less error-prone.  You could even
  423.  * <tt>return</tt> while still holding the lock and it will be released
  424.  * properly.
  425.  */
  426. class Mutex::Lock
  427. {
  428. public:
  429.   explicit inline Lock(Mutex& mutex);
  430.   inline Lock(Mutex& mutex, NotLock);
  431.   inline Lock(Mutex& mutex, TryLock);
  432.   inline ~Lock();
  433.  
  434.   inline void acquire();
  435.   inline bool try_acquire();
  436.   inline void release();
  437.   inline bool locked() const;
  438.  
  439. private:
  440.   Mutex&  mutex_;
  441.   bool    locked_;
  442.  
  443.   // noncopyable
  444.   Lock(const Mutex::Lock&);
  445.   Mutex::Lock& operator=(const Mutex::Lock&);
  446. };
  447.  
  448.  
  449. /** Like Glib::RecMutex, but can be defined at compile time.
  450.  * Use @c GLIBMM_STATIC_REC_MUTEX_INIT to initialize a StaticRecMutex:
  451.  * @code
  452.  * Glib::StaticRecMutex mutex = GLIBMM_STATIC_REC_MUTEX_INIT;
  453.  * @endcode
  454.  * A StaticRecMutex can be used without calling Glib::thread_init(), it will
  455.  * silently do nothing then.  That will also work when using the implicit
  456.  * conversion to RecMutex&, thus you can safely use RecMutex::Lock with a
  457.  * StaticRecMutex.
  458.  */
  459. struct StaticRecMutex
  460. {
  461.   void lock();
  462.   bool trylock();
  463.   void unlock();
  464.  
  465.   void lock_full(unsigned int depth);
  466.   unsigned int unlock_full();
  467.  
  468.   operator RecMutex&();
  469.  
  470.   GStaticRecMutex* gobj() { return &gobject_; }
  471.  
  472. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  473.   // Must be public to allow initialization at compile time.
  474.   GStaticRecMutex gobject_;
  475. #endif
  476. };
  477.  
  478. class RecMutex : public StaticRecMutex
  479. {
  480. public:
  481.   class Lock;
  482.  
  483.   RecMutex();
  484.   ~RecMutex();
  485.  
  486. private:
  487.   // noncopyable
  488.   RecMutex(const RecMutex&);
  489.   RecMutex& operator=(const RecMutex&);
  490. };
  491.  
  492. /** Utility class for exception-safe locking of recursive mutexes.
  493.  */
  494. class RecMutex::Lock
  495. {
  496. public:
  497.   explicit inline Lock(RecMutex& mutex);
  498.   inline Lock(RecMutex& mutex, NotLock);
  499.   inline Lock(RecMutex& mutex, TryLock);
  500.   inline ~Lock();
  501.  
  502.   inline void acquire();
  503.   inline bool try_acquire();
  504.   inline void release();
  505.   inline bool locked() const;
  506.  
  507. private:
  508.   RecMutex& mutex_;
  509.   bool      locked_;
  510.  
  511.   // noncopyable
  512.   Lock(const RecMutex::Lock&);
  513.   RecMutex::Lock& operator=(const RecMutex::Lock&);
  514. };
  515.  
  516.  
  517. /** Like Glib::RWLock, but can be defined at compile time.
  518.  * Use @c GLIBMM_STATIC_RW_LOCK_INIT to initialize a StaticRWLock:
  519.  * @code
  520.  * Glib::StaticRWLock rw_lock = GLIBMM_STATIC_RW_LOCK_INIT;
  521.  * @endcode
  522.  * A StaticRWLock can be used without calling Glib::thread_init(), it will
  523.  * silently do nothing then.  That will also work when using the implicit
  524.  * conversion to RWLock&, thus you can safely use RWLock::ReaderLock and
  525.  * RWLock::WriterLock with a StaticRWLock.
  526.  */
  527. struct StaticRWLock
  528. {
  529.   void reader_lock();
  530.   bool reader_trylock();
  531.   void reader_unlock();
  532.  
  533.   void writer_lock();
  534.   bool writer_trylock();
  535.   void writer_unlock();
  536.  
  537.   operator RWLock&();
  538.  
  539.   GStaticRWLock* gobj() { return &gobject_; }
  540.  
  541. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  542.   // Must be public to allow initialization at compile time.
  543.   GStaticRWLock gobject_;
  544. #endif
  545. };
  546.  
  547. class RWLock : public StaticRWLock
  548. {
  549. public:
  550.   class ReaderLock;
  551.   class WriterLock;
  552.  
  553.   RWLock();
  554.   ~RWLock();
  555.  
  556. private:
  557.   // noncopyable
  558.   RWLock(const RWLock&);
  559.   RWLock& operator=(const RWLock&);
  560. };
  561.  
  562. /** Utility class for exception-safe locking of read/write locks.
  563.  */
  564. class RWLock::ReaderLock
  565. {
  566. public:
  567.   explicit inline ReaderLock(RWLock& rwlock);
  568.   inline ReaderLock(RWLock& rwlock, NotLock);
  569.   inline ReaderLock(RWLock& rwlock, TryLock);
  570.   inline ~ReaderLock();
  571.  
  572.   inline void acquire();
  573.   inline bool try_acquire();
  574.   inline void release();
  575.   inline bool locked() const;
  576.  
  577. private:
  578.   RWLock& rwlock_;
  579.   bool    locked_;
  580.  
  581.   // noncopyable
  582.   ReaderLock(const RWLock::ReaderLock&);
  583.   RWLock::ReaderLock& operator=(const RWLock::ReaderLock&);
  584. };
  585.  
  586. /** Utility class for exception-safe locking of read/write locks.
  587.  */
  588. class RWLock::WriterLock
  589. {
  590. public:
  591.   explicit inline WriterLock(RWLock& rwlock);
  592.   inline WriterLock(RWLock& rwlock, NotLock);
  593.   inline WriterLock(RWLock& rwlock, TryLock);
  594.   inline ~WriterLock();
  595.  
  596.   inline void acquire();
  597.   inline bool try_acquire();
  598.   inline void release();
  599.   inline bool locked() const;
  600.  
  601. private:
  602.   RWLock& rwlock_;
  603.   bool    locked_;
  604.  
  605.   // noncopyable
  606.   WriterLock(const RWLock::WriterLock&);
  607.   RWLock::WriterLock& operator=(const RWLock::WriterLock&);
  608. };
  609.  
  610. /** An opaque data structure to represent a condition. 
  611.  * A @a Cond is an object that threads can block on, if they find a certain 
  612.  * condition to be false. If other threads change the state of this condition 
  613.  * they can signal the @a Cond, such that the waiting thread is woken up.
  614.  * @par Usage example:
  615.  * @code
  616.  * Glib::Cond data_cond;
  617.  * Glib::Mutex data_mutex;
  618.  * void* current_data = NULL;
  619.  * 
  620.  * void push_data (void* data)
  621.  * {
  622.  *   data_mutex.lock();
  623.  *   current_data = data;
  624.  *   data_cond.signal();
  625.  *   data_mutex.unlock();
  626.  * }
  627.  * 
  628.  * void* pop_data ()
  629.  * {
  630.  *   void* data;
  631.  * 
  632.  *   data_mutex.lock();
  633.  *   while (!current_data)
  634.  *       data_cond.wait(data_mutex);
  635.  *   data = current_data;
  636.  *   current_data = NULL;
  637.  *   data_mutex.unlock();
  638.  *   return data;
  639.  * }
  640.  * @endcode
  641. */
  642. class Cond
  643. {
  644. public:
  645.   Cond();
  646.   ~Cond();
  647.  
  648.   /** If threads are waiting for this @a Cond, exactly one of them is woken up. 
  649.    * It is good practice to hold the same lock as the waiting thread, while calling 
  650.    * this method, though not required.
  651.    *
  652.    * @note This method can also be used if @a Glib::thread_init() has not yet been 
  653.    * called and will do nothing then.
  654.    */
  655.   void signal();
  656.  
  657.   /** If threads are waiting for this @a Cond, all of them are woken up.
  658.    * It is good practice to hold the same lock as the waiting thread, while calling 
  659.    * this method, though not required.
  660.    *
  661.    * @note This method can also be used if @a Glib::thread_init() has not yet been 
  662.    * called and will do nothing then.
  663.    */
  664.   void broadcast();
  665.  
  666.   /** Waits until this thread is woken up on this @a Cond.
  667.    * The mutex is unlocked before falling asleep and locked again before resuming.
  668.    *
  669.    * This method can also be used if @a Glib::thread_init() has not yet been 
  670.    * called and will immediately return then. 
  671.    *
  672.    * @param mutex a @a Mutex that is currently locked.
  673.    * 
  674.    * @note It is important to use the @a wait() and @a timed_wait() methods
  675.    * only inside a loop, which checks for the condition to be true as it is not 
  676.    * guaranteed that the waiting thread will find it fulfilled, even if the signaling 
  677.    * thread left the condition in that state. This is because another thread can have 
  678.    * altered the condition, before the waiting thread got the chance to be woken up, 
  679.    * even if the condition itself is protected by a @a Mutex.
  680.    */
  681.   void wait(Mutex& mutex);
  682.  
  683.   /** Waits until this thread is woken up on this @a Cond, but not longer than until the time, that is specified by @a abs_time.
  684.    * The mutex is unlocked before falling asleep and locked again before resuming.
  685.    *
  686.    * This function can also be used, if @a Glib::thread_init() has not yet been 
  687.    * called and will immediately return @c true then. 
  688.    *
  689.    * @param mutex a @a Mutex that is currently locked.
  690.    * @param abs_time a max time to wait.
  691.    * 
  692.    * @note It is important to use the @a wait() and @a timed_wait() methods
  693.    * only inside a loop, which checks for the condition to be true as it is not 
  694.    * guaranteed that the waiting thread will find it fulfilled, even if the signaling 
  695.    * thread left the condition in that state. This is because another thread can have 
  696.    * altered the condition, before the waiting thread got the chance to be woken up, 
  697.    * even if the condition itself is protected by a @a Mutex.
  698.    */
  699.   bool timed_wait(Mutex& mutex, const Glib::TimeVal& abs_time);
  700.  
  701.   GCond* gobj() { return gobject_; }
  702.  
  703. private:
  704.   GCond* gobject_;
  705.  
  706.   // noncopyable
  707.   Cond(const Cond&);
  708.   Cond& operator=(const Cond&);
  709. };
  710.  
  711.  
  712. template <class T>
  713. struct StaticPrivate
  714. {
  715.   typedef void (*DestroyNotifyFunc) (void*);
  716.  
  717.   static void delete_ptr(void* data);
  718.  
  719.   inline T* get();
  720.   inline void set(T* data, DestroyNotifyFunc notify_func = &StaticPrivate<T>::delete_ptr);
  721.  
  722.   GStaticPrivate* gobj() { return &gobject_; }
  723.  
  724. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  725.   // Must be public to allow initialization at compile time.
  726.   GStaticPrivate gobject_;
  727. #endif
  728. };
  729.  
  730. template <class T>
  731. class Private
  732. {
  733. public:
  734.   typedef void (*DestructorFunc) (void*);
  735.  
  736.   static void delete_ptr(void* data);
  737.  
  738.   explicit inline Private(DestructorFunc destructor_func = &Private<T>::delete_ptr);
  739.   inline T* get();
  740.   inline void set(T* data);
  741.  
  742.   GPrivate* gobj() { return gobject_; }
  743.  
  744. private:
  745.   GPrivate* gobject_;
  746.  
  747.   // noncopyable
  748.   Private(const Private<T>&);
  749.   Private<T>& operator=(const Private<T>&);
  750. };
  751.  
  752. /** @} group Threads */
  753.  
  754. /*! A glibmm thread example.
  755.  * @example thread/thread.cc
  756.  */
  757.  
  758.  
  759. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  760.  
  761. /***************************************************************************/
  762. /*  inline implementation                                                  */
  763. /***************************************************************************/
  764.  
  765. // internal
  766. void thread_init_impl();
  767.  
  768. /* This function must be inline, to avoid an unnecessary dependency on
  769.  * libgthread even if the thread system is not used.  libgthread might
  770.  * not even be available if GLib was compiled without thread support.
  771.  */
  772. inline
  773. void thread_init(GThreadFunctions* vtable)
  774. {
  775.   g_thread_init(vtable);
  776.   Glib::thread_init_impl();
  777. }
  778.  
  779. inline
  780. bool thread_supported()
  781. {
  782.   //MSVC++ needs the != 0 to avoid an int -> bool cast warning.
  783.   return (g_thread_supported() != 0);
  784. }
  785.  
  786.  
  787. /**** Glib::Mutex::Lock ****************************************************/
  788.  
  789. inline
  790. Mutex::Lock::Lock(Mutex& mutex)
  791. :
  792.   mutex_  (mutex),
  793.   locked_ (true)
  794. {
  795.   mutex_.lock();
  796. }
  797.  
  798. inline
  799. Mutex::Lock::Lock(Mutex& mutex, NotLock)
  800. :
  801.   mutex_  (mutex),
  802.   locked_ (false)
  803. {}
  804.  
  805. inline
  806. Mutex::Lock::Lock(Mutex& mutex, TryLock)
  807. :
  808.   mutex_  (mutex),
  809.   locked_ (mutex.trylock())
  810. {}
  811.  
  812. inline
  813. Mutex::Lock::~Lock()
  814. {
  815.   if(locked_)
  816.     mutex_.unlock();
  817. }
  818.  
  819. inline
  820. void Mutex::Lock::acquire()
  821. {
  822.   mutex_.lock();
  823.   locked_ = true;
  824. }
  825.  
  826. inline
  827. bool Mutex::Lock::try_acquire()
  828. {
  829.   locked_ = mutex_.trylock();
  830.   return locked_;
  831. }
  832.  
  833. inline
  834. void Mutex::Lock::release()
  835. {
  836.   mutex_.unlock();
  837.   locked_ = false;
  838. }
  839.  
  840. inline
  841. bool Mutex::Lock::locked() const
  842. {
  843.   return locked_;
  844. }
  845.  
  846.  
  847. /**** Glib::RecMutex::Lock *************************************************/
  848.  
  849. inline
  850. RecMutex::Lock::Lock(RecMutex& mutex)
  851. :
  852.   mutex_  (mutex),
  853.   locked_ (true)
  854. {
  855.   mutex_.lock();
  856. }
  857.  
  858. inline
  859. RecMutex::Lock::Lock(RecMutex& mutex, NotLock)
  860. :
  861.   mutex_  (mutex),
  862.   locked_ (false)
  863. {}
  864.  
  865. inline
  866. RecMutex::Lock::Lock(RecMutex& mutex, TryLock)
  867. :
  868.   mutex_  (mutex),
  869.   locked_ (mutex.trylock())
  870. {}
  871.  
  872. inline
  873. RecMutex::Lock::~Lock()
  874. {
  875.   if(locked_)
  876.     mutex_.unlock();
  877. }
  878.  
  879. inline
  880. void RecMutex::Lock::acquire()
  881. {
  882.   mutex_.lock();
  883.   locked_ = true;
  884. }
  885.  
  886. inline
  887. bool RecMutex::Lock::try_acquire()
  888. {
  889.   locked_ = mutex_.trylock();
  890.   return locked_;
  891. }
  892.  
  893. inline
  894. void RecMutex::Lock::release()
  895. {
  896.   mutex_.unlock();
  897.   locked_ = false;
  898. }
  899.  
  900. inline
  901. bool RecMutex::Lock::locked() const
  902. {
  903.   return locked_;
  904. }
  905.  
  906.  
  907. /**** Glib::RWLock::ReaderLock *********************************************/
  908.  
  909. inline
  910. RWLock::ReaderLock::ReaderLock(RWLock& rwlock)
  911. :
  912.   rwlock_ (rwlock),
  913.   locked_ (true)
  914. {
  915.   rwlock_.reader_lock();
  916. }
  917.  
  918. inline
  919. RWLock::ReaderLock::ReaderLock(RWLock& rwlock, NotLock)
  920. :
  921.   rwlock_ (rwlock),
  922.   locked_ (false)
  923. {}
  924.  
  925. inline
  926. RWLock::ReaderLock::ReaderLock(RWLock& rwlock, TryLock)
  927. :
  928.   rwlock_ (rwlock),
  929.   locked_ (rwlock.reader_trylock())
  930. {}
  931.  
  932. inline
  933. RWLock::ReaderLock::~ReaderLock()
  934. {
  935.   if(locked_)
  936.     rwlock_.reader_unlock();
  937. }
  938.  
  939. inline
  940. void RWLock::ReaderLock::acquire()
  941. {
  942.   rwlock_.reader_lock();
  943.   locked_ = true;
  944. }
  945.  
  946. inline
  947. bool RWLock::ReaderLock::try_acquire()
  948. {
  949.   locked_ = rwlock_.reader_trylock();
  950.   return locked_;
  951. }
  952.  
  953. inline
  954. void RWLock::ReaderLock::release()
  955. {
  956.   rwlock_.reader_unlock();
  957.   locked_ = false;
  958. }
  959.  
  960. inline
  961. bool RWLock::ReaderLock::locked() const
  962. {
  963.   return locked_;
  964. }
  965.  
  966.  
  967. /**** Glib::RWLock::WriterLock *********************************************/
  968.  
  969. inline
  970. RWLock::WriterLock::WriterLock(RWLock& rwlock)
  971. :
  972.   rwlock_ (rwlock),
  973.   locked_ (true)
  974. {
  975.   rwlock_.writer_lock();
  976. }
  977.  
  978. inline
  979. RWLock::WriterLock::WriterLock(RWLock& rwlock, NotLock)
  980. :
  981.   rwlock_ (rwlock),
  982.   locked_ (false)
  983. {}
  984.  
  985. inline
  986. RWLock::WriterLock::WriterLock(RWLock& rwlock, TryLock)
  987. :
  988.   rwlock_ (rwlock),
  989.   locked_ (rwlock.writer_trylock())
  990. {}
  991.  
  992. inline
  993. RWLock::WriterLock::~WriterLock()
  994. {
  995.   if(locked_)
  996.     rwlock_.writer_unlock();
  997. }
  998.  
  999. inline
  1000. void RWLock::WriterLock::acquire()
  1001. {
  1002.   rwlock_.writer_lock();
  1003.   locked_ = true;
  1004. }
  1005.  
  1006. inline
  1007. bool RWLock::WriterLock::try_acquire()
  1008. {
  1009.   locked_ = rwlock_.writer_trylock();
  1010.   return locked_;
  1011. }
  1012.  
  1013. inline
  1014. void RWLock::WriterLock::release()
  1015. {
  1016.   rwlock_.writer_unlock();
  1017.   locked_ = false;
  1018. }
  1019.  
  1020. inline
  1021. bool RWLock::WriterLock::locked() const
  1022. {
  1023.   return locked_;
  1024. }
  1025.  
  1026.  
  1027. /**** Glib::StaticPrivate **************************************************/
  1028.  
  1029. // static
  1030. template <class T>
  1031. void StaticPrivate<T>::delete_ptr(void* data)
  1032. {
  1033.   delete static_cast<T*>(data);
  1034. }
  1035.  
  1036. template <class T> inline
  1037. T* StaticPrivate<T>::get()
  1038. {
  1039.   return static_cast<T*>(g_static_private_get(&gobject_));
  1040. }
  1041.  
  1042. template <class T> inline
  1043. void StaticPrivate<T>::set(T* data, typename StaticPrivate<T>::DestroyNotifyFunc notify_func)
  1044. {
  1045.   g_static_private_set(&gobject_, data, notify_func);
  1046. }
  1047.  
  1048.  
  1049. /**** Glib::Private ********************************************************/
  1050.  
  1051. // static
  1052. template <class T>
  1053. void Private<T>::delete_ptr(void* data)
  1054. {
  1055.   delete static_cast<T*>(data);
  1056. }
  1057.  
  1058. template <class T> inline
  1059. Private<T>::Private(typename Private<T>::DestructorFunc destructor_func)
  1060. :
  1061.   gobject_ (g_private_new(destructor_func))
  1062. {}
  1063.  
  1064. template <class T> inline
  1065. T* Private<T>::get()
  1066. {
  1067.   return static_cast<T*>(g_private_get(gobject_));
  1068. }
  1069.  
  1070. template <class T> inline
  1071. void Private<T>::set(T* data)
  1072. {
  1073.   g_private_set(gobject_, data);
  1074. }
  1075.  
  1076. #endif /* DOXYGEN_SHOULD_SKIP_THIS */
  1077.  
  1078. } // namespace Glib
  1079.  
  1080.  
  1081. #endif /* _GLIBMM_THREAD_H */
  1082.  
  1083.